﻿#region changelog
/*
 * 02/04/09 - wbw (Seagull Consulting): Original code
 * 02/15/09 - wbw: Added Series Name Alias functionality
 * 02/20/09 - wbw : Add functionality to accept templateXMLFileName and SeriesAliasFileName
 * 03/16/09 - wbw : Changed Alias lookup to be case independent
 * 03/22/09 - wbw : Additional ToUpper needed to make Alias lookup case independent
 * 11/22/11 - as : Replaced xml fetch to use WebRequest/WebResponse with gzip encryption to address 'random gzip response' issue with thetvdb.com API
 */
#endregion

using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using Durrant.Common;
using System.Net;
using System.Web;
using System.IO.Compression;

namespace Durrant.Plugins.TvDB
{
    public static class TVDB
    {
        public static string APIKey { get; set; }
        public static string SeriesId { get; set; }
        public static string EpisodeId { get; set; }
        public static string TemplateXMLFileName { get; set; }
        public static string SeriesAliasFileName { get; set; }
        private static Hashtable SeriesAlias = new Hashtable();

        public static void init()
        {
            XmlDocument doc = null;
            XmlTextReader reader = null;
            XmlNode node = null;
            string seriesXMLName, seriesXMLAlias = string.Empty;

            try
            {
                reader = new XmlTextReader(SeriesAliasFileName);
                doc = new XmlDocument();
                reader.WhitespaceHandling = WhitespaceHandling.None;
                reader.MoveToContent();
                doc.Load(reader);
                node = doc.FirstChild;
               for (int i = 0; i < node.ChildNodes.Count; i++)
                {
                    if (node.ChildNodes[i].Name == Constants.TORRENT_NAME_XML)
                    {
                        seriesXMLName = node.ChildNodes[i].Attributes[Constants.SERIES_ATTRIBUTE_NAME].Value;
                        seriesXMLAlias = node.ChildNodes[i].Attributes[Constants.SERIES_ATTRIBUTE_ALIAS].Value;
                        SeriesAlias.Add(seriesXMLName.ToUpper(), seriesXMLAlias);
                    }
                }
                
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TBDB.init: Unable to read configuration file: " + ex.Message);
                Debug.WriteLine(ex.ToString());
            }
        }

        public static bool setSeriesId(string seriesName)
        {
            StringBuilder seriesXML = new StringBuilder();
            string nodeName = string.Empty;
            string url = string.Empty;
            bool status = true;
            XmlTextReader reader = null;

            try
            {
                //Check if the series has an alias, the use it
                if (SeriesAlias.ContainsKey(seriesName.ToUpper()))
                    seriesName = (string)SeriesAlias[seriesName.ToUpper()];

                // formulate thetvdb.com query url
                url = Constants.TVDB_BASE_URL + Constants.TVDB_GET_SERIES_BY_NAME;
                url = String.Format(url, seriesName);

                // Query thetvdb.com for the xml
                MemoryStream memoryStream = getTVDBXml(url);

                // create the XmlTextReader using the response xml stream
                reader = new XmlTextReader(memoryStream);

                parseSeriesIdXml(reader);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TBDB.setSeriesId Exception: " + ex.Message);
                Debug.WriteLine(ex.ToString());
                status = false;
            }
            finally
            {
                if (reader != null) reader.Close();
            }

            return status;
        }

        public static string getSeriesXMLById()
        {
            string url = string.Empty;
            XmlTextReader reader = null;

            try
            {
                // formulate thetvdb.com query url
                url = Constants.TVDB_BASE_URL + Constants.TVDB_GET_SERIES_BY_ID;
                url = String.Format(url, TVDB.APIKey, SeriesId);

                // Query thetvdb.com for the xml
                MemoryStream memoryStream = getTVDBXml(url);

                // create the XmlTextReader using the response xml stream
                reader = new XmlTextReader(memoryStream);

                return parseSeriesXml(reader);
                
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TBDB.getSeriesXMLById Exception: " + ex.Message);
                Debug.WriteLine(ex.ToString());
            }
            finally
            {
                if (reader != null) reader.Close();
            }

            return string.Empty;
        }

        public static string getEpisodeXML(string season, string episode)
        {
            string url = string.Empty;
            XmlTextReader reader = null;

            try
            {
                // formulate thetvdb.com query url
                url = Constants.TVDB_BASE_URL + Constants.TVDB_GET_EPISODE;
                url = String.Format(url, TVDB.APIKey, SeriesId, Convert.ToInt16(season).ToString(), Convert.ToInt16(episode).ToString());

                // Query thetvdb.com for the xml
                MemoryStream memoryStream = getTVDBXml(url);

                // create the XmlTextReader using the response xml stream
                reader = new XmlTextReader(memoryStream);
                
                return parseEpisodeXml(reader);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TVDB.getEpisodeXML Exception: " + ex.Message);
                Debug.WriteLine(ex.ToString());
            }
            finally
            {
                if (reader != null) reader.Close();
            }

            return string.Empty;
        }

        private static MemoryStream getTVDBXml(string url)
        {
            //fetch xml using webrequest - force gzip compression encoding
            WebRequest webRequest = WebRequest.Create(url);

            lows.Info(string.Format("Fetching TVDBXml from url {0}", url.Replace(TVDB.APIKey, "**apiKey**")));

            webRequest.Headers[HttpRequestHeader.AcceptEncoding] = "gzip";
            WebResponse webResponse = webRequest.GetResponse();

            // decompress the responseStream
            MemoryStream memoryStream = CompressionHelper.decompressGZipStream(webResponse.GetResponseStream());
            return memoryStream;
        }

        private static void parseSeriesIdXml(XmlTextReader reader)
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                    if (reader.Name == Constants.SERIES_ID)
                    {
                        reader.Read();
                        SeriesId = reader.Value;
                        break;
                    }
            }
        }

        private static string parseSeriesXml(XmlTextReader reader)
        {
            StringBuilder xmlBuilder = new StringBuilder();
            string tabPrefix = string.Empty;

            try
            {
                while (reader.Read())
                {
                    // Write the start tag and innerXML
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        tabPrefix = new string('\t', reader.Depth);
                        xmlBuilder.Append(tabPrefix + "<" + reader.Name + ">");
                        reader.Read();
                        if (reader.Value != null)
                            xmlBuilder.Append(reader.Value + '\r' + '\n');
                        else
                            xmlBuilder.Append('\r' + '\n');
                    }
                    else
                    {
                        // Write the end tag
                        if (reader.NodeType == XmlNodeType.EndElement)
                        {
                            tabPrefix = new string('\t', reader.Depth);
                            xmlBuilder.Append(tabPrefix + "</" + reader.Name + ">" + '\r' + '\n');
                        }
                    }
                } //end of while
            }
            catch (Exception e)
            {
                Debug.WriteLine("TVDB.ParseXML Exception: " + e.Message);
                Debug.WriteLine(e.ToString());
                throw e;
            }

            return xmlBuilder.ToString();
        }

        private static string parseEpisodeXml(XmlTextReader reader)
        {
            StringBuilder xmlBuilder = new StringBuilder();
            string tabPrefix = string.Empty;

            try
            {
                while (reader.Read())
                {
                    // Write the start tag and innerXML
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        tabPrefix = new string('\t', reader.Depth);
                        xmlBuilder.Append(tabPrefix + "<" + reader.Name + ">");
                        reader.Read();
                        if (reader.Value != null)
                            xmlBuilder.Append(reader.Value + '\r' + '\n');
                        else
                            xmlBuilder.Append('\r' + '\n');
                    }
                    else
                    {
                        // Write the end tag
                        if (reader.NodeType == XmlNodeType.EndElement)
                        {
                            tabPrefix = new string('\t', reader.Depth);
                            xmlBuilder.Append(tabPrefix + "</" + reader.Name + ">" + '\r' + '\n');
                        }
                    }
                } //end of while
            }
            catch (Exception e)
            {
                Debug.WriteLine("TVDB.parseEpisodeXmlStream Exception: " + e.Message);
                Debug.WriteLine(e.ToString());
                throw e;
            }
            
            return xmlBuilder.ToString();
        }
    }
}
